package com.qs.cwams.util;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;

/**
 * @author suncheng
 */
public class TimeSlot {

    private LocalDateTime startTime;

    private long start;

    private LocalDateTime endTime;

    private long end;

    public TimeSlot() {}

    public TimeSlot(LocalDateTime startTime, LocalDateTime endTime) {
        this.startTime = startTime;
        this.endTime = endTime;
        this.start = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        this.end = endTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public TimeSlot(long start, long end) {
        this.start = start;
        this.end = end;
        this.startTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(start), ZoneId.systemDefault());
        this.endTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(end), ZoneId.systemDefault());
    }

    public boolean overlapsWith(TimeSlot other) {
        return this.start <= other.end && this.end >= other.start;
    }

    public boolean contain(TimeSlot other) {
        return this.start <= other.start && this.end >= other.end;
    }

    public TimeSlot merge(TimeSlot other) {
        return overlapsWith(other) ? new TimeSlot(Math.min(this.start, other.start), Math.max(this.end, other.end)) : null;
    }

    public TimeSlot intersect(TimeSlot other) {
        return overlapsWith(other) ? new TimeSlot(Math.max(this.start, other.start), Math.min(this.end, other.end)) : null;
    }

    public long duration() {
        return Duration.between(startTime, endTime).toMinutes();
    }

    public List<TimeSlot> exclude(TimeSlot other) {
        List<TimeSlot> slots = new ArrayList<>();
        if (overlapsWith(other)) {
            if (this.start < other.start && this.end > other.start)  {
                slots.add(new TimeSlot(this.start, other.start));
            }

            if (this.end > other.end && this.start < other.end) {
                slots.add(new TimeSlot(other.end, this.end));
            }
        }
        return slots;
    }

    public LocalDateTime getStartTime() {
        return startTime;
    }

    public void setStartTime(LocalDateTime startTime) {
        this.startTime = startTime;
        this.start = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public long getStart() {
        return start;
    }

    public void setStart(long start) {
        this.start = start;
        this.startTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(start), ZoneId.systemDefault());
    }

    public LocalDateTime getEndTime() {
        return endTime;
    }

    public void setEndTime(LocalDateTime endTime) {
        this.endTime = endTime;
        this.end = endTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public long getEnd() {
        return end;
    }

    public void setEnd(long end) {
        this.end = end;
        this.endTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(end), ZoneId.systemDefault());
    }
}
